package mmc.resource.models.collada;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import org.collada.x2005.x11.colladaSchema.COLLADADocument;
import org.collada.x2005.x11.colladaSchema.InputLocalOffset;
import org.collada.x2005.x11.colladaSchema.MeshDocument.Mesh;
import org.collada.x2005.x11.colladaSchema.PolygonsDocument.Polygons;
import org.collada.x2005.x11.colladaSchema.PolylistDocument.Polylist;
import org.collada.x2005.x11.colladaSchema.TrianglesDocument.Triangles;

public class ColladaTriangleMeshGenerator{
	
	static class Vertex{
		float x,y,z,nx,ny,nz,tx,ty;
		
		public Vertex(TriangleMesh tm, ColladaFloatDataSource vertex, ColladaFloatDataSource normals, ColladaFloatDataSource texCoord, int index){
			x = vertex.get(index, 0);
			y = vertex.get(index, 1);
			z = vertex.get(index, 2);
			
			if(tm.hasNormals){
				nx = normals.get(index, 0);
				ny = normals.get(index, 1);
				nz = normals.get(index, 2);
			}
			
			if(tm.hasTexCoords){
				tx = 1-texCoord.get(index, 0);
				ty = 1-texCoord.get(index, 1);
			}
		}
	}
	
	static class TriangleMesh{
		boolean hasTexCoords;
		boolean hasNormals;
		List<Vertex> vertices = new ArrayList<Vertex>();
	}
	
	@SuppressWarnings("unchecked")
	public static TriangleMesh generateTriangleMesh(COLLADADocument doc, Mesh mesh, Polylist polylist) {
		TriangleMesh tm = new TriangleMesh();
		ColladaFloatDataSource vertex = null, texCoord = null, normals = null;
		int elements = polylist.getCount().intValue();
		int indexStride = 1;
		List<BigInteger> index = polylist.getP();
		List<BigInteger> vertexCount = polylist.getVcount();
		
		for(InputLocalOffset i : polylist.getInputArray()){
			if(i.getSemantic().equals("TEXCOORD")){
				tm.hasTexCoords = true;
				texCoord = new ColladaFloatDataSource(mesh,i,index);
				indexStride++;
			}else if(i.getSemantic().equals("VERTEX")){
				vertex = new ColladaFloatDataSource(mesh,i,index);
			}else if(i.getSemantic().equals("NORMAL")){
				tm.hasNormals = true;
				normals = new ColladaFloatDataSource(mesh,i,index);
				indexStride++;
			}else{
				throw new RuntimeException("Unknown Semantic: "+i.getSemantic());
			}
		}
		
		if(vertex == null)
			throw new RuntimeException("No vertex souce found in mesh!");
		
		if(tm.hasTexCoords) texCoord.indexStride = indexStride;
		if(tm.hasNormals) normals.indexStride = indexStride;
		vertex.indexStride = indexStride;
		
		int offset = 0;
		for(int i=0;i<elements;i++){ //each element
			int vCountLocal = vertexCount.get(i).intValue();
			for(int v=2;v<vCountLocal;v++){ //each triangle
				tm.vertices.add(new Vertex(tm,vertex,normals,texCoord,offset));
				tm.vertices.add(new Vertex(tm,vertex,normals,texCoord,offset+v-1));
				tm.vertices.add(new Vertex(tm,vertex,normals,texCoord,offset+v));
			}
			offset += vCountLocal;
		}
		
		return tm;
	}

	@SuppressWarnings("unchecked")
	public static TriangleMesh generateTriangleMesh(COLLADADocument doc, Mesh mesh, Polygons polygons) {
		TriangleMesh tm = new TriangleMesh();
		ColladaFloatDataSource vertex = null, texCoord = null, normals = null;
		int indexStride = 1;
		
		for(InputLocalOffset i : polygons.getInputArray()){
			if(i.getSemantic().equals("TEXCOORD")){
				tm.hasTexCoords = true;
				texCoord = new ColladaFloatDataSource(mesh,i,null);
				indexStride++;
			}else if(i.getSemantic().equals("VERTEX")){
				vertex = new ColladaFloatDataSource(mesh,i,null);
			}else if(i.getSemantic().equals("NORMAL")){
				tm.hasNormals = true;
				normals = new ColladaFloatDataSource(mesh,i,null);
				indexStride++;
			}else{
				throw new RuntimeException("Unknown Semantic: "+i.getSemantic());
			}
		}
		
		if(vertex == null)
			throw new RuntimeException("No vertex souce found in mesh!");
		
		if(tm.hasTexCoords) texCoord.indexStride = indexStride;
		if(tm.hasNormals) normals.indexStride = indexStride;
		vertex.indexStride = indexStride;
		
		for(List<BigInteger> i : (List<BigInteger>[])polygons.getPArray()){
			int vCountLocal = i.size()/indexStride;
			vertex.index = i;
			if(tm.hasNormals) normals.index = i;
			if(tm.hasTexCoords) texCoord.index = i;
			
			for(int v=2;v<vCountLocal;v++){ //each triangle
				tm.vertices.add(new Vertex(tm,vertex,normals,texCoord,0));
				tm.vertices.add(new Vertex(tm,vertex,normals,texCoord,v-1));
				tm.vertices.add(new Vertex(tm,vertex,normals,texCoord,v));
			}
		}
		
		return tm;
	}

	@SuppressWarnings("unchecked")
	public static TriangleMesh generateTriangleMesh(COLLADADocument doc, Mesh mesh, Triangles t) {
		TriangleMesh tm = new TriangleMesh();
		ColladaFloatDataSource vertex = null, texCoord = null, normals = null;
		int elements = t.getCount().intValue();
		int indexStride = 1;
		List<BigInteger> index = t.getP();
		
		for(InputLocalOffset i : t.getInputArray()){
			if(i.getSemantic().equals("TEXCOORD")){
				tm.hasTexCoords = true;
				texCoord = new ColladaFloatDataSource(mesh,i,index);
				indexStride++;
			}else if(i.getSemantic().equals("VERTEX")){
				vertex = new ColladaFloatDataSource(mesh,i,index);
			}else if(i.getSemantic().equals("NORMAL")){
				tm.hasNormals = true;
				normals = new ColladaFloatDataSource(mesh,i,index);
				indexStride++;
			}else{
				throw new RuntimeException("Unknown Semantic: "+i.getSemantic());
			}
		}
		
		if(vertex == null)
			throw new RuntimeException("No vertex souce found in mesh!");
		
		if(tm.hasTexCoords) texCoord.indexStride = indexStride;
		if(tm.hasNormals) normals.indexStride = indexStride;
		vertex.indexStride = indexStride;
		
		int offset = 0;
		for(int i=0;i<elements;i++){ //each element
			tm.vertices.add(new Vertex(tm,vertex,normals,texCoord,offset));
			tm.vertices.add(new Vertex(tm,vertex,normals,texCoord,offset+1));
			tm.vertices.add(new Vertex(tm,vertex,normals,texCoord,offset+2));
			offset += 3;
		}
		
		return tm;
	}
}